package com.example.gaojt.androiddemo.quickBoost;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.RectF;
import android.os.SystemClock;
import android.support.annotation.Nullable;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;
import android.view.animation.LinearInterpolator;

import com.example.gaojt.androiddemo.R;

import java.util.ArrayList;
import java.util.Random;

/**
 * Created by gaojt on 8/4/17.
 */

public class QuickBoostView extends View {

    private static final String TAG = "QuickBoostView";
    private Bitmap mBottomBitmap;
    private Bitmap mCenterBitmap;
    private Paint mBubblePaint;
    private float mBubbleRadius;

    public QuickBoostView(Context context) {
        this(context, null);
    }

    public QuickBoostView(Context context, @Nullable AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public QuickBoostView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        mBottomBitmap = BitmapFactory.decodeResource(getResources(), R.mipmap.boostengine_ring_icon);
        mCenterBitmap = BitmapFactory.decodeResource(getResources(), R.mipmap.boostengine_center_icon);
        mBubblePaint = new Paint();
        mBubblePaint.setColor(Color.WHITE);
        mBubblePaint.setStyle(Paint.Style.FILL);
        mBubbleRadius = getResources().getDimension(R.dimen.bubble_radius);
        mRandom = new Random(SystemClock.currentThreadTimeMillis());
    }

    private BitmapAnim mBitmapAnim;

    class BitmapBubbleAnim extends Animation {

        private Rect src;
        private RectF dst;
        private Bitmap bitmap;
        float startX;
        float startY;
        float endX;
        float endY;
        float progress;

        public BitmapBubbleAnim(Bitmap bitmap, float dstW, float dstH, float sx, float sy, float ex, float ey) {
            this.bitmap = bitmap;
            startX = sx;
            startY = sy;
            endX = ex;
            endY = ey;
            src = new Rect(0, 0, bitmap.getWidth(), bitmap.getHeight());
            dst = new RectF(ex - dstW / 2, ey - dstH / 2, ex + dstW / 2, ey + dstH / 2);
            setInterpolator(new LinearInterpolator());
        }

        @Override
        protected void onCalculate(float progress) {
            this.progress = progress;
        }

        public void draw(Canvas canvas) {
            float tx = (endX - startX) * (1 - progress);
            float ty = (endY - startY) * (1 - progress);
            canvas.translate(-tx, -ty);
            float offsetX = (dst.width() * (1 - progress * 0.8f)) / 2;
            float offsetY = (dst.height() * (1 - progress * 0.8f)) / 2;
            dst.set(dst.centerX() - offsetX, dst.centerY() - offsetY, dst.centerX() + offsetX, dst.centerY() + offsetY);
            canvas.drawBitmap(bitmap, src, dst, null);
            canvas.translate(tx, ty);
        }
    }

    class BitmapAnim extends Animation {

        int startX;
        int startY;
        int endX;
        int endY;
        float progress;

        public BitmapAnim(int sx, int sy, int ex, int ey) {
            startX = sx;
            startY = sy;
            endX = ex;
            endY = ey;
            setDuration(2000);
            setInterpolator(new LinearInterpolator());
        }

        @Override
        protected void onCalculate(float progress) {
            this.progress = progress;
        }

        public void draw(Canvas canvas) {
            float tx = startX + (endX - startX) * (1 - progress);
            float ty = startY + (endY - startY) * (1 - progress);
            canvas.translate(-tx, -ty);
            canvas.scale(progress, progress);
            canvas.drawBitmap(mBottomBitmap, mBottomBitmapDst.left, mBottomBitmapDst.top, null);
            canvas.translate(tx, ty);
        }
    }

    class BubbleAnim extends Animation {

        float radius;
        float fraction;
        float startX, startY;
        float endX, endY;

        public BubbleAnim(float startX, float startY, float endX, float endY, float radius) {
            this.radius = radius;
            this.startX = startX;
            this.startY = startY;
            this.endX = endX;
            this.endY = endY;
            setInterpolator(new LinearInterpolator());
        }

        @Override
        protected void onCalculate(float progress) {
            fraction = progress;
        }

        public void draw(Canvas canvas, Paint paint) {
            int push = paint.getAlpha();
            paint.setAlpha((int) (255 * (1 - fraction)));
            float x = startX + (endX - startX) * fraction;
            float y = startY + (endY - startY) * fraction;
            canvas.drawCircle(x, y, radius * (1 - fraction), paint);
            paint.setAlpha(push);
        }
    }

    private RectF mBottomBitmapDst = new RectF();
    private RectF mCenterBitmapDst = new RectF();

    private Random mRandom;

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        float bottomBitmapLeft = (w - mBottomBitmap.getWidth()) / 2;
        float bottomBitmapTop = (h - mBottomBitmap.getHeight()) / 2;
        mBottomBitmapDst.set(bottomBitmapLeft, bottomBitmapTop, bottomBitmapLeft + mBottomBitmap.getWidth(),
                bottomBitmapTop + mBottomBitmap.getHeight());

        float centerBitmapLeft = (w - mCenterBitmap.getWidth()) / 2;
        float centerBitmapTop = (h - mCenterBitmap.getHeight()) / 2;
        mCenterBitmapDst.set(centerBitmapLeft, centerBitmapTop, centerBitmapLeft + mCenterBitmap.getWidth(),
                centerBitmapTop + mCenterBitmap.getHeight());

        mBitmapAnim = new BitmapAnim(0, 0, w / 2, h / 2);
        mBitmapAnim.start();
    }

    private float degrees = 0;

    private static final float mPopFactor = 0.02f;

    private ArrayList<BubbleAnim> mBubbleAnimList = new ArrayList<>();
    private ArrayList<BubbleAnim> mDelBubbleAnimList = new ArrayList<>();

    private ArrayList<BitmapBubbleAnim> mBitmapBubbleAnimList = new ArrayList<>();
    private ArrayList<BitmapBubbleAnim> mDelBitmapBubbleAnimList = new ArrayList<>();

    private int mOrientation = 1;

    private void genBitmapBubble(Bitmap bitmap) {
        float f = mRandom.nextFloat();
        if (f > (1 - mPopFactor)) {
            int index = mRandom.nextInt(4);
            int offsetX = mRandom.nextInt((getWidth() - mBottomBitmap.getWidth()) / 6);
            int offsetY = mRandom.nextInt((getHeight() - mBottomBitmap.getHeight()) / 6);

            float pointX = 0;
            float pointY = 0;
            if (index == 0) {
                pointX = mBottomBitmapDst.left - (10 + offsetX);
                pointY = mBottomBitmapDst.top - mOrientation * offsetY;
            } else if (index == 1) {
                pointX = mBottomBitmapDst.right + (10 + offsetX);
                pointY = mBottomBitmapDst.top - mOrientation * offsetY;
            } else if (index == 2) {
                pointX = mBottomBitmapDst.right + (10 + offsetX);
                pointY = mBottomBitmapDst.bottom - mOrientation * offsetY;
            } else {
                pointX = mBottomBitmapDst.left - (10 + offsetX);
                pointY = mBottomBitmapDst.bottom - mOrientation * offsetY;
            }
            int size = mRandom.nextInt(20) + 60;
            float scale = size * (1.0f) / bitmap.getWidth();
            float centerX = getWidth() / 2.0f;
            float centerY = getHeight() / 2.0f;
            BitmapBubbleAnim anim = new BitmapBubbleAnim(bitmap, scale * bitmap.getWidth(), scale * bitmap.getHeight(), pointX,
                    pointY, centerX, centerY);
            anim.setDuration(300 + mRandom.nextInt(20) * 10);
            anim.start();
            mBitmapBubbleAnimList.add(anim);
        }
    }

    private void genBubble() {
        float f = mRandom.nextFloat();
        if (f > (1 - mPopFactor)) {
            int index = mRandom.nextInt(4);
            int offsetX = mRandom.nextInt((getWidth() - mBottomBitmap.getWidth()) / 6);
            int offsetY = mRandom.nextInt((getHeight() - mBottomBitmap.getHeight()) / 6);

            float pointX = 0;
            float pointY = 0;
            if (index == 0) {
                pointX = mBottomBitmapDst.left - (10 + offsetX);
                pointY = mBottomBitmapDst.top - mOrientation * offsetY;
            } else if (index == 1) {
                pointX = mBottomBitmapDst.right + (10 + offsetX);
                pointY = mBottomBitmapDst.top - mOrientation * offsetY;
            } else if (index == 2) {
                pointX = mBottomBitmapDst.right + (10 + offsetX);
                pointY = mBottomBitmapDst.bottom - mOrientation * offsetY;
            } else {
                pointX = mBottomBitmapDst.left - (10 + offsetX);
                pointY = mBottomBitmapDst.bottom - mOrientation * offsetY;
            }
            mOrientation *= -1;
            float randR = mRandom.nextInt(20) + 10;
            float centerX = getWidth() / 2.0f;
            float centerY = getHeight() / 2.0f;
            BubbleAnim anim = new BubbleAnim(pointX, pointY, centerX, centerY, randR);
            anim.setDuration(300 + mRandom.nextInt(20) * 10);
            anim.start();
            mBubbleAnimList.add(anim);
        }
    }


    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        long s = System.currentTimeMillis();
        try {
            if (getWidth() == 0 || getHeight() == 0) {
                return;
            }
            if (mBottomBitmapDst.isEmpty() || mCenterBitmapDst.isEmpty()) {
                return;
            }
            canvas.drawColor(Color.BLACK);
            genBubble();
            genBitmapBubble(mCenterBitmap);
            AnimationTime.update();
            mDelBubbleAnimList.clear();
            for (BubbleAnim bubbleAnim : mBubbleAnimList) {
                boolean finish = !bubbleAnim.calculate(AnimationTime.get());
                if (finish) {
                    mDelBubbleAnimList.add(bubbleAnim);
                }
            }
            mBubbleAnimList.removeAll(mDelBubbleAnimList);

            for (BitmapBubbleAnim anim : mBitmapBubbleAnimList) {
                boolean finish = !anim.calculate(AnimationTime.get());
                if (finish) {
                    mDelBitmapBubbleAnimList.add(anim);
                }
            }
            mBitmapBubbleAnimList.removeAll(mDelBitmapBubbleAnimList);

            degrees += 15;
            canvas.rotate(degrees, getWidth() / 2, getHeight() / 2);
            canvas.drawBitmap(mBottomBitmap, mBottomBitmapDst.left, mBottomBitmapDst.top, null);
            canvas.rotate(-degrees, getWidth() / 2, getHeight() / 2);
            for (BubbleAnim bubbleAnim : mBubbleAnimList) {
                bubbleAnim.draw(canvas, mBubblePaint);
            }

            for (BitmapBubbleAnim anim : mBitmapBubbleAnimList) {
                anim.draw(canvas);
            }

            canvas.drawBitmap(mCenterBitmap, mCenterBitmapDst.left, mCenterBitmapDst.top, null);
            // if (mBitmapAnim != null) {
            // mBitmapAnim.calculate(AnimationTime.get());
            // mBitmapAnim.draw(canvas);
            // invalidate();
            // }
            invalidate();

        } finally {
            Log.d(TAG, "onDraw: time = " + (System.currentTimeMillis() - s));
        }


    }


}
